<?php
namespace core\models;
/**
 * 数据库 增、删、改、查快速类
 * @author ZhouHaoHua <53027327@qq.com>
 * @date   2014-2-13
 */
abstract class DB {
    /**
     * Database_Action 类句柄
     * @var Database_Action
     */
    protected $_db;
    /**
     * 表名称
     * @var string
     */
    protected $_table;

    /**
     * 存放初始化后可能重复用到的对象
     * @var array
     * @author lwkai
     * @date   2015-10-14
     */
    protected $_obj = array();
    /**
     * 禁止更新的字段。如：['pk_id', 'goods_id']
     * @var array
     */
    protected $readOnlyFields = [];
    /**
     * 自动时间戳。自动写入【新增时】add_date和【更新时】last_date两个字段的值（如果表中有这两字段的话）。可设置为：datetime | int | false
     * @var bool | string
     */
    protected $autoWriteTimestamp = false;
    public function __construct() {
        $this->init();
        if (!$this->_table) {
            throw \Z::Error('请传入表名');
        }
        $this->_db = Database_Action::getDb();
    }

    /**
     * 初始化
     */
    public function init(){
        if(empty($this->_table)){   // 自动获取当前类对应的数据表名
            $this->_table = strtolower(get_class($this));
        }
    }
    /**
     * 获取一个类，初始化之后会缓存，下次不再初始化，循环中如果初始化则会多次。
     * @param string $class_name 类名
     * @author lwkai
     * @date   2015-10-14
     */
    protected function getObj($class_name) {
        if (!isset($this->_obj[$class_name])) {
            $this->_obj[$class_name] = new $class_name();
        }
        return $this->_obj[$class_name];
    }

    /**
     * 删除记录
     * @param string|array|Number $where 删除条件，可以是条件数组、条件串或主键值。如：[id => 156, key => 999] 或 id=156 或 156
     * @return boolean|number
     */
    public function delete($where) {
        return $this->_db->delete($this->_table, $where);
    }

    /**
     * 获取一条记录
     * @param int|string|array $where 查询条件
     * @return boolean|array
     */
    public function getOne($where) {
        return $this->_db->getOne($this->_table, $where);
    }

    /**
     * 修改
     * @param array            $data  要修改的字段和值key为字段名，val为字段值。
     * @param int|string|array $where 更新的条件，条件字符串或只传主键值或数组。如：id=896 或 896
     * @return int 返回被更新的记录数
     */
    public function update(array $data, $where) {
        if($this->autoWriteTimestamp!==false && !isset($data['last_date'])){
            switch($this->autoWriteTimestamp){
                case 'datetime' : $data['last_date'] = date('Y-m-d H:i:s');
                    break;
                case 'int' :
                default:
                    $data['last_date'] = time();
                    break;
            }
        }

        if(!empty($this->readOnlyFields)){
            foreach($this->readOnlyFields as $field){
                unset($data[$field]);
            }
        }

        return $this->_db->update($this->_table, $data, $where);
    }

    /**
     * 数据更新前排除那些不想被更新的字段。
     * 此方法应该用在update()之前，把返回的数据给到update去更新
     * @param array $fields 那些不可更新的字段集。如['a','b']将排除a和b这两个字段
     * @param array $data 数据来源
     * @return array  返回清洁过后的数据
     * @author ZhouHaoHua <53027327@qq.com>
     * @date 2020-09-23 23:01:16
     */
    public function updateBeforeExcludeFields(array $fields, array $data){
        $fields = array_flip($fields);
        return array_diff_key($data, $fields);
    }
    /**
     * 增加记录
     * @param array $data 表单数组
     * @return number 返回自增的主键id值
     */
    public function insert(array $data) {
        if($this->autoWriteTimestamp!==false && !isset($data['add_date'])){
            switch($this->autoWriteTimestamp){
                case 'datetime' : $data['add_date'] = date('Y-m-d H:i:s');
                    break;
                case 'int' :
                default:
                    $data['add_date'] = time();
                    break;
            }
        }
        $key_id = $this->_db->insert($this->_table, $data);
        return $key_id;
    }

    /**
     * 取列表
     * 【这只是最简单的列表，随便取10条】
     * @author ZhouHaoHua <53027327@qq.com>
     * @param int $limit
     * @return array
     */
    public function getList($limit) {
        $this->_db->addTable($this->_table);
        if ($limit != 'all' && is_numeric($limit)) {
            $this->_db->addLimit($limit);
        }
        return $this->_db->getList();
    }
    /**
     * 分页列表
     * 【这只是列出简单的分页列表】
     * @param array  $where 条件数组。如：['orders_id'=>15, 'last_modified >'=>"2014-12-24 06:14:37"]
     * @param int    $num 每页显示几条记录？
     * @param string $order_by 排序方式字符串，如：orders_id ASC
     * @param string $GROUP_BY 聚合方式，如：agents_id或agents_id, agents_name
     * @return array 返回二维数组
     * @author ZhouHaoHua <53027327@qq.com>
     */
    public function getPageList(array $where = array(), $num = 10, $order_by = null, $GROUP_BY = null) {
        return $this->_db->addField('*')->addWhere($where)->addTable($this->_table)->addOrderBy($order_by)->addGroupBy($GROUP_BY)->getPageList($num);
    }
}